
namespace Classes
{
	//////////////////////////////////////////////////////////////////////////
	//  AsyncCallback [template]
	//
	//  Description:
	//  Helper class that routes IMFAsyncCallback::Invoke calls to a class
	//  method on the parent class.
	//
	//  Usage:
	//  Add this class as a member variable. In the parent class constructor,
	//  initialize the AsyncCallback class like this:
	//      m_cb(this, &CYourClass::OnInvoke)
	//  where
	//      m_cb       = AsyncCallback object
	//      CYourClass = parent class
	//      OnInvoke   = Method in the parent class to receive Invoke calls.
	//
	//  The parent's OnInvoke method (you can name it anything you like) must
	//  have a signature that matches the InvokeFn typedef below.
	//////////////////////////////////////////////////////////////////////////

	// T: Type of the parent object
	template<class T>
	class AsyncCallback : public IMFAsyncCallback
	{
	public:
		typedef HRESULT (T::*InvokeFn)(IMFAsyncResult *pAsyncResult);

		AsyncCallback(T *pParent, InvokeFn fn) : m_pParent(pParent), m_pInvokeFn(fn)
		{
		}

		// IUnknown
		STDMETHODIMP QueryInterface(REFIID iid, void** ppv)
		{
			if (!ppv)
			{
				return E_POINTER;
			}
			if (iid == __uuidof(IUnknown))
			{
				*ppv = static_cast<IUnknown*>(static_cast<IMFAsyncCallback*>(this));
			}
			else if (iid == __uuidof(IMFAsyncCallback))
			{
				*ppv = static_cast<IMFAsyncCallback*>(this);
			}
			else
			{
				*ppv = NULL;
				return E_NOINTERFACE;
			}
			AddRef();
			return S_OK;
		}
		STDMETHODIMP_(ULONG) AddRef() {
			// Delegate to parent class.
			return m_pParent->AddRef();
		}
		STDMETHODIMP_(ULONG) Release() {
			// Delegate to parent class.
			return m_pParent->Release();
		}


		// IMFAsyncCallback methods
		STDMETHODIMP GetParameters(DWORD*, DWORD*)
		{
			// Implementation of this method is optional.
			return E_NOTIMPL;
		}

		STDMETHODIMP Invoke(IMFAsyncResult* pAsyncResult)
		{
			return (m_pParent->*m_pInvokeFn)(pAsyncResult);
		}

		T *m_pParent;
		InvokeFn m_pInvokeFn;
	};
}